import java.io.*;
import java.util.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;
import javax.microedition.lcdui.*;
import javax.wireless.messaging.MessageConnection;
import javax.wireless.messaging.TextMessage;
import net.dclausen.microfloat.*;

/** Interpreter workspace */
public class WorkSpace  {
    /* librarySpace: pointers to library procedures
     * procSpace: procedure table. holds (procedure name, parent node)
     * reservedKeywords: better scanning, lookup reservedKeywords
     * symTab: symbole table. (variable name : String, value : Value)
     * fileHandlers: file connection handlers table
     */
    public static Hashtable librarySpace, procSpace, reservedKeyworks, symTab, fileHandlers;
    public static Stack stack = null; // runtime stack; paramter passing; etc..
    public static String fsroot = "file:///store/home/user/zam/"; // working directory
    public static int color = 0x00FFFFFF; // color white
    public static Font font; // graphix screen font
    /* breakFlag: raised upon EXIT; contFlag: raised upon CONTINUE
     * inReady: screen I/O; fill: FILLON/OFF
     */
    public static boolean breakFlag = false, contFlag = false, inReady = false, fill = false;
    public static CellularBASIC parent = null; // pointer to parent MIDlet
    public static Graphics g = null; // pointer to graphix screen graphics pen
    static Display display = null; // this display
    static int u0 = 0, v0 = 0, paramNumber = 0; // utilities
    
    public static Thread IOThread = null, socketThread = null; // threads ...
    public static DataOutputStream dos = null; // ... and streams ...
    public static DataInputStream dis = null; // ... for file/socket I/O
    
    static TextField outTextField, inTextField; // pointer to I/O adapters
    static int ErrorLine, ErrorColumn;
    static String ErrorMessage;
    static StringBuffer outTextBuffer; // double buffering of stdout
    // handlers for builtin's
    public final static short ACOS = 1001;
    public final static short ASIN = 1002;
    public final static short ATAN = 1003;
    public final static short COS = 1004;
    public final static short SIN = 1005;
    public final static short TAN = 1006;
    public final static short ACOSH = 1007;
    public final static short ASINH = 1008;
    public final static short ATANH = 1009;
    public final static short COSH = 1010;
    public final static short SINH = 1011;
    public final static short TANH = 1012;
    public final static short RAD = 1041;
    public final static short DEG = 1042;
    
    public final static short ABS = 1013;
    public final static short BIN$ = 1014;
    
    public final static short MAX = 1015;
    public final static short MIN = 1016;
    public final static short MOD = 1017;
    public final static short RND = 1018;
    public final static short SIGN = 1019;
    
    public final static short SQRT = 1020;
    
    public final static short EXP = 1021;
    public final static short LOG10 = 1022;
    public final static short LN = 1023;
    public final static short LOG = 1024;
    
    public final static short COMBINATIONS = 1025;
    public final static short PERMUTATIONS = 1026;
    public final static short ROUND = 1027; // *
    public final static short FRAC = 1028; // *
    public final static short CEIL = 1029; //*
    public final static short FLOOR = 1030; //*
    public final static short FIX = 1030; //
    public final static short INT = 1030; //
    
    public final static short TIMEMILLI = 1034;
    public final static short TIME = 1036;
    public final static short DATE = 1037;
    public final static short TOTALMEM = 1038;
    public final static short FREEMEM = 1039;
    public final static short GC = 1040;
    
    public final static short PSET = 1031;
    public final static short LINE = 1032;
    public final static short CLS = 1033;
    public final static short AXIS = 1035;
    public final static short CIRCLE = 1043;
    public final static short ARC = 1044;
    public final static short FILLON = 1045;
    public final static short FILLOFF = 1046;
    public final static short WIDTH = 1055;
    public final static short HEIGHT = 1056;
    public final static short MOVER = 1058;
    public final static short PSETR = 1059;
    public final static short COLOR = 1065;
    
    public final static short LEFT = 1047;
    public final static short RIGHT = 1048;
    public final static short MID = 1049;
    public final static short LEN = 1050;
    public final static short LCASE = 1051;
    public final static short UCASE = 1052;
    public final static short ASC = 1053;
    public final static short CHR = 1054;
    public final static short INSTR = 1057;
    public final static short VAL = 1060;
    
    public final static short SOCKET = 1061;
    public final static short SREAD = 1062;
    public final static short SWRITE = 1063;
    public final static short SCLOSE = 1064;
    public final static short CLOSE = 1066; // close file
    public final static short SMS = 1067;
    
    public final static short RUN = 1068;
    
    /** install a procedure in procSpace table
     *  @param key name of procedure. stored as UPPER case
     *  @param val pointer to root node of procedure (type = sub)
     */
    public static void putProc(Object key, Object val) {
        procSpace.put(key.toString().toUpperCase(), val);
    }
    
    /** get procedure */
    public static Object getProc(Object key) {
        Object node = procSpace.get(key.toString().toUpperCase());
        if(node != null) {
            return node;
        }
        return null;
    }
    
    /** install a variable in symbole table
     *  @param key name of variable. stored as UPPER case
     *  @param val value (Value) of variable
     */
    public static void putVar(Object key, Object val) {
        symTab.put(key.toString().toUpperCase(), val);
    }
    
    /** install array element */
    public static void putArrayElement(Object key, Value index, Value val) {
        int __index = MicroDouble.intValue(index.dVal); // get the index
        Vector v = null;
        if (symTab.containsKey(key.toString().toUpperCase()) == true) {
            try {
                v = (Vector)symTab.get(key.toString().toUpperCase());
                if (v.size() < __index) { v.setSize(__index + 1); } // if size<index: expand the array
                v.setElementAt(val, __index - 1);
                symTab.put(key.toString().toUpperCase(), v);
                return;
            } catch(Exception e) {}
        }
        v = new Vector(__index); // if new array
        v.setSize(__index);
        v.setElementAt(val, __index - 1);
        symTab.put(key.toString().toUpperCase(), v);
    }
    
    public static Value getVar(Object key) {
        Value ste = (Value)symTab.get(key.toString().toUpperCase());
        if (ste != null) { return ste; }
        return new Value(MicroDouble.ZERO);
    }
    
    public static void delVar(Object key) {
        symTab.remove(key);
    }
    
    /** initialize workspace */
    public static void initialize(CellularBASIC par) {
        parent = par;
        g = parent.gScreen.offscreen.getGraphics();
        font = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL);
        display = Display.getDisplay(parent);
        stack = new Stack();
        
        outTextBuffer = new StringBuffer();
        symTab = new Hashtable();
        reservedKeyworks = new Hashtable();
        librarySpace = new Hashtable();
        procSpace = new Hashtable();
        fileHandlers = new Hashtable();
        initializeReserved(); // initialize reserved keywords
        initializeLibrary(); // initialize builtin's
    }
    
    /** lookup a reserved keyword */
    public static short lookup(Object sym) {
        Object obj = reservedKeyworks.get(sym.toString().toUpperCase());
        if (obj == null) {
            // if not a reserved keyword, return ID
            return Parser.ID;
        } else {
            // otherwise, a reserved keyword associated pointer
            return ((Short)obj).shortValue();
        }
    }
    
    /** lookup a builtin */
    public static short libraryContains(Object sym) {
        if (librarySpace.containsKey(sym.toString().toUpperCase()) == false) {
            return 0;
        } else {
            return ((Short)librarySpace.get(sym.toString().toUpperCase())).shortValue();
        }
    }
    
    /** initialize builtin table */
    public static void initializeLibrary() {
        librarySpace.put("ABS", new Short(ABS));
        
//        librarySpace.put("BIN$", new Short(BIN$));
        
        librarySpace.put("EXP", new Short(EXP));
        librarySpace.put("LOG", new Short(LOG));
        librarySpace.put("LN", new Short(LN));
        librarySpace.put("LOG10", new Short(LOG10));
        
        librarySpace.put("FRAC", new Short(FRAC));
        librarySpace.put("CEIL", new Short(CEIL));
        librarySpace.put("FLOOR", new Short(FLOOR));
        librarySpace.put("FIX", new Short(FLOOR));
        librarySpace.put("INT", new Short(FLOOR));
        librarySpace.put("ROUND", new Short(ROUND));
        
        librarySpace.put("MAX", new Short(MAX));
        librarySpace.put("MIN", new Short(MIN));
        librarySpace.put("MOD", new Short(MOD));
//      librarySpace.put("SIGN", new Short(SIGN));
        
        librarySpace.put("SQRT", new Short(SQRT));
        librarySpace.put("RND", new Short(RND));
        
        librarySpace.put("COS", new Short(COS));
        librarySpace.put("SIN", new Short(SIN));
        librarySpace.put("ACOS", new Short(ACOS));
        librarySpace.put("ASIN", new Short(ASIN));
        librarySpace.put("ATAN", new Short(ATAN));
        librarySpace.put("TAN", new Short(TAN));
        librarySpace.put("COSH", new Short(COSH));
        librarySpace.put("SINH", new Short(SINH));
        librarySpace.put("ACOSH", new Short(ACOSH));
        librarySpace.put("ASINH", new Short(ASINH));
        librarySpace.put("ATANH", new Short(ATANH));
        librarySpace.put("TANH", new Short(TANH));
        librarySpace.put("RAD", new Short(RAD));
        librarySpace.put("DEG", new Short(DEG));
        
        librarySpace.put("COMBINATIONS", new Short(COMBINATIONS));
        librarySpace.put("PERMUTATIONS", new Short(PERMUTATIONS));
        
        librarySpace.put("PSET", new Short(PSET));
        librarySpace.put("LINE", new Short(LINE));
        librarySpace.put("CLS", new Short(CLS));
        librarySpace.put("AXIS", new Short(AXIS));
        librarySpace.put("CIRCLE", new Short(CIRCLE));
        librarySpace.put("ARC", new Short(ARC));
        librarySpace.put("FILLOFF", new Short(FILLOFF));
        librarySpace.put("FILLON", new Short(FILLON));
        librarySpace.put("WIDTH", new Short(WIDTH));
        librarySpace.put("HEIGHT", new Short(HEIGHT));
        librarySpace.put("MOVER", new Short(MOVER));
        librarySpace.put("PSETR", new Short(PSETR));
        librarySpace.put("COLOR", new Short(COLOR));
        
        librarySpace.put("TIMEMILLI", new Short(TIMEMILLI));
        librarySpace.put("DATE", new Short(DATE));
        librarySpace.put("TIME", new Short(TIME));
        librarySpace.put("FREEMEM", new Short(FREEMEM));
        librarySpace.put("TOTALMEM", new Short(TOTALMEM));
        librarySpace.put("GC", new Short(GC));
        
        librarySpace.put("LEFT$", new Short(LEFT));
        librarySpace.put("RIGHT$", new Short(RIGHT));
        librarySpace.put("MID$", new Short(MID));
        librarySpace.put("LEN", new Short(LEN));
        librarySpace.put("LCASE$", new Short(LCASE));
        librarySpace.put("UCASE$", new Short(UCASE));
        librarySpace.put("ASC", new Short(ASC));
        librarySpace.put("CHR$", new Short(CHR));
        librarySpace.put("INSTR", new Short(INSTR));
        librarySpace.put("VAL", new Short(VAL));
        
        librarySpace.put("SOCKET", new Short(SOCKET));
        librarySpace.put("SCLOSE", new Short(SCLOSE));
        librarySpace.put("SREAD", new Short(SREAD));
        librarySpace.put("SWRITE", new Short(SWRITE));
        librarySpace.put("CLOSE", new Short(CLOSE));
        librarySpace.put("SMS", new Short(SMS));
        
        librarySpace.put("RUN", new Short(RUN));
    }
    
    /** initialize keywords table */
    public static void initializeReserved() {
        reservedKeyworks.put("NOT", new Short(Parser.NOT));
        reservedKeyworks.put("AND", new Short(Parser.AND));
        reservedKeyworks.put("OR", new Short(Parser.OR));
        reservedKeyworks.put("XOR", new Short(Parser.XOR));
        reservedKeyworks.put("XNOR", new Short(Parser.XNOR));
        
        reservedKeyworks.put("IF", new Short(Parser.IF));
        reservedKeyworks.put("THEN", new Short(Parser.THEN));
        reservedKeyworks.put("ELSE", new Short(Parser.ELSE));
        reservedKeyworks.put("END", new Short(Parser.END));
        reservedKeyworks.put("WHILE", new Short(Parser.WHILE));
        reservedKeyworks.put("WEND", new Short(Parser.WEND));
        reservedKeyworks.put("DO", new Short(Parser.DO));
        reservedKeyworks.put("LOOP", new Short(Parser.LOOP));
        reservedKeyworks.put("UNTIL", new Short(Parser.UNTIL));
        reservedKeyworks.put("FOR", new Short(Parser.FOR));
        reservedKeyworks.put("TO", new Short(Parser.TO));
        reservedKeyworks.put("STEP", new Short(Parser.STEP));
        reservedKeyworks.put("CALL", new Short(Parser.CALL));
        reservedKeyworks.put("SUB", new Short(Parser.SUB));
        reservedKeyworks.put("FUNCTION", new Short(Parser.SUB));
        
        reservedKeyworks.put("SELECT", new Short(Parser.SELECT));
        reservedKeyworks.put("CASE", new Short(Parser.CASE));
        reservedKeyworks.put("BREAK", new Short(Parser.BREAK));
        reservedKeyworks.put("EXIT", new Short(Parser.BREAK));
        reservedKeyworks.put("CONTINUE", new Short(Parser.CONTINUE));
        reservedKeyworks.put("NEXT", new Short(Parser.NEXT));
        
        reservedKeyworks.put("PRINT", new Short(Parser.PRINT));
        reservedKeyworks.put("INPUT", new Short(Parser.INPUT));
        
        reservedKeyworks.put("TRUE", new Short(Parser.TRUE));
        reservedKeyworks.put("FALSE", new Short(Parser.FALSE));
        
        reservedKeyworks.put("OPEN", new Short(Parser.OPEN));
        reservedKeyworks.put("AS", new Short(Parser.AS));
    }
    
    
    public static void dump(Hashtable h) {
        Enumeration e = h.keys();
        System.out.println("ID\t\tvalue");
        Object k = null;
        while(e.hasMoreElements()) {
            k = e.nextElement();
            System.out.println(k + "\t\t" + ((Value)h.get(k)).dVal);
        }
    }
    
    public WorkSpace() {
    }
    
    /** execute builtin on Node o1, type of library builtin = o1.type */
    public synchronized static Value execLib(Object o1) throws Exception {
        Node root = (Node) o1; // workhorse
        Node param = null;
        long r01 = 0, r02 = 0; // utility
        Value returnVal = new Value();
        switch (root.type) { // check node type
            case ABS:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.abs(r01);
                returnVal.type = Value.NUM;
                break;
            case RAD:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.toRadians(r01);
                returnVal.type = Value.NUM;
                break;
            case DEG:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.toDegrees(r01);
                returnVal.type = Value.NUM;
                break;
            case ACOS:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.acos(r01);
                returnVal.type = Value.NUM;
                break;
            case ASIN:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.asin(r01);
                returnVal.type = Value.NUM;
                break;
            case ATAN:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.atan(r01);
                returnVal.type = Value.NUM;
                break;
            case BIN$:
            case COS:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.cos(r01);
                returnVal.type = Value.NUM;
                break;
            case EXP:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.exp(r01);
                returnVal.type = Value.NUM;
                break;
            case FLOOR:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.floor(r01);
                returnVal.type = Value.NUM;
                break;
            case CEIL:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.ceil(r01);
                returnVal.type = Value.NUM;
                break;
            case FRAC:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                if (MicroDouble.lt(r01, MicroDouble.ZERO) == true) {
                    returnVal.dVal = MicroDouble.sub(r01, MicroDouble.ceil(r01));
                } else {
                    returnVal.dVal = MicroDouble.sub(r01, MicroDouble.floor(r01));
                }
                returnVal.type = Value.NUM;
                break;
            case MOD:
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.mod(r01, r02);
                returnVal.type = Value.NUM;
                break;
            case ROUND:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.floor(MicroDouble.add(r01, MicroDouble.ONE_HALF));
                returnVal.type = Value.NUM;
                break;
            case LOG10:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.log10(r01);
                returnVal.type = Value.NUM;
                break;
            case LOG:
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.log(r01, r02); // note order: # then base
                returnVal.type = Value.NUM;
                break;
            case LN:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.log(r01);
                returnVal.type = Value.NUM;
                break;
            case MAX:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.max(r01, r02);
                returnVal.type = Value.NUM;
                break;
            case MIN:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.min(r01, r02);
                returnVal.type = Value.NUM;
                break;
            case RND:
                returnVal.dVal = MicroDouble.random();
                returnVal.type = Value.NUM;
                break;
            case SIGN:
            case SIN:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.sin(r01);
                returnVal.type = Value.NUM;
                break;
            case SQRT:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.sqrt(r01);
                returnVal.type = Value.NUM;
                break;
            case TAN:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.tan(r01);
                returnVal.type = Value.NUM;
                break;
            case ASINH:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.asinh(r01);
                returnVal.type = Value.NUM;
                break;
            case ACOSH:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.acosh(r01);
                returnVal.type = Value.NUM;
                break;
            case ATANH:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.atanh(r01);
                returnVal.type = Value.NUM;
                break;
            case COSH:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.cosh(r01);
                returnVal.type = Value.NUM;
                break;
            case SINH:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.sinh(r01);
                returnVal.type = Value.NUM;
                break;
            case TANH:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.tanh(r01);
                returnVal.type = Value.NUM;
                break;
            case COMBINATIONS:
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.combinations(r01, r02);
                returnVal.type = Value.NUM;
                break;
            case PERMUTATIONS:
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                returnVal.dVal = MicroDouble.permutations(r01, r02);
                returnVal.type = Value.NUM;
                break;
            case CLS:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                parent.gScreen.cls();
                outTextBuffer.setLength(0);
                outTextField.setString("");
                break;
            case AXIS:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                parent.gScreen.axis();
                break;
            case MOVER:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                u0 = MicroDouble.intValue(r01);
                v0 = MicroDouble.intValue(r02);
                parent.gScreen.repaint();
                break;
            case PSETR:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                g.setColor(color);
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                int u = MicroDouble.intValue(r01);
                int v = MicroDouble.intValue(r02);
                g.drawLine(u, v, u0, v0);
                u0 = u; v0 = v;
                parent.gScreen.repaint();
                break;
            case COLOR:
                param = root.child[0];
                param.exec();
                long r03 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                u = MicroDouble.intValue(r01);
                v = MicroDouble.intValue(r02);
                int w = MicroDouble.intValue(r03);
                g.setColor(u, v, w);
                color = g.getColor();
                break;
            case PSET:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                g.setColor(color);
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                u = MicroDouble.intValue(r01);
                v = MicroDouble.intValue(r02);
                g.drawLine(u, v, u, v);
                parent.gScreen.repaint();
                break;
            case LINE:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                param = root.child[0];
                param.exec();
                g.setColor(color);
                long r04 = ((Value)stack.pop()).dVal;
                r03 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                g.drawLine(MicroDouble.intValue(r01), MicroDouble.intValue(r02),
                        MicroDouble.intValue(r03), MicroDouble.intValue(r04));
                parent.gScreen.repaint();
                break;
            case CIRCLE:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                g.setColor(color);
                param = root.child[0];
                param.exec();
                r03 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                int r = MicroDouble.intValue(r03);
                if (fill == false) {
                    g.drawArc(MicroDouble.intValue(r01) - r, MicroDouble.intValue(r02) - r,
                            2*r, 2*r, 0, 360);
                } else {
                    g.fillArc(MicroDouble.intValue(r01) - r, MicroDouble.intValue(r02) - r,
                            2*r, 2*r, 0, 360); }
                parent.gScreen.repaint();
                break;
            case ARC:
                if (parent.gScreen.isShown() == false) {
                    display.setCurrent(parent.gScreen); }
                g.setColor(color);
                param = root.child[0];
                param.exec();
                long r05 = ((Value)stack.pop()).dVal;
                r04 = ((Value)stack.pop()).dVal;
                r03 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                r01 = ((Value)stack.pop()).dVal;
                r = MicroDouble.intValue(r03);
                if (fill == false) {
                    g.drawArc(MicroDouble.intValue(r01) - r, MicroDouble.intValue(r02) - r,
                            2*r, 2*r,  MicroDouble.intValue(r04),  MicroDouble.intValue(r05));
                } else {
                    g.fillArc(MicroDouble.intValue(r01) - r, MicroDouble.intValue(r02) - r,
                            2*r, 2*r,  MicroDouble.intValue(r04),  MicroDouble.intValue(r05)); }
                parent.gScreen.repaint();
                break;
            case FILLON:
                fill = true;
                break;
            case FILLOFF:
                fill = false;
                break;
            case WIDTH:
                returnVal.dVal = MicroDouble.longToDouble(parent.gScreen.getWidth());
                returnVal.type = Value.NUM;
                break;
            case HEIGHT:
                returnVal.dVal = MicroDouble.longToDouble(parent.gScreen.getHeight());
                returnVal.type = Value.NUM;
                break;
            case TIMEMILLI:
                returnVal.dVal = MicroDouble.longToDouble(System.currentTimeMillis());
                returnVal.type = Value.NUM;
                break;
            case TIME:
                // dow mon dd hh:mm:ss zzz yyyy
                // 0123456789012345678901234567
                returnVal.sVal = new Date().toString().substring(11, 19);
                returnVal.type = Value.TXT;
                break;
            case DATE:
                String now = new Date().toString();
                returnVal.sVal = now.substring(0, 10) + " " + now.substring(24, 28);
                returnVal.type = Value.TXT;
                break;
            case FREEMEM:
                returnVal.dVal = MicroDouble.longToDouble(Runtime.getRuntime().freeMemory());
                returnVal.type = Value.NUM;
                break;
            case TOTALMEM:
                returnVal.dVal = MicroDouble.longToDouble(Runtime.getRuntime().totalMemory());
                returnVal.type = Value.NUM;
                break;
            case GC:
                System.gc();
                break;
            case LEFT:
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                String src = ((Value)stack.pop()).sVal;
                returnVal.sVal = src.substring(0, MicroDouble.intValue(r02));
                returnVal.type = Value.TXT;
                break;
            case RIGHT:
                param = root.child[0];
                param.exec();
                r02 = ((Value)stack.pop()).dVal;
                src = ((Value)stack.pop()).sVal;
                returnVal.sVal = src.substring(src.length() - MicroDouble.intValue(r02), src.length());
                returnVal.type = Value.TXT;
                break;
            case MID:
                param = root.child[0];
                param.exec();
                r03 = ((Value)stack.pop()).dVal;
                r02 = ((Value)stack.pop()).dVal;
                src = ((Value)stack.pop()).sVal;
                returnVal.sVal = src.substring(MicroDouble.intValue(r02) - 1,
                        MicroDouble.intValue(r02) + MicroDouble.intValue(r03) - 1);
                returnVal.type = Value.TXT;
                break;
            case LEN:
                param = root.child[0];
                param.exec();
                returnVal.dVal = MicroDouble.intToDouble(((Value)stack.pop()).sVal.length());
                returnVal.type = Value.NUM;
                break;
            case LCASE:
                param = root.child[0];
                param.exec();
                src = ((Value)stack.pop()).sVal;
                returnVal.sVal = src.toLowerCase();
                returnVal.type = Value.TXT;
                break;
            case UCASE:
                param = root.child[0];
                param.exec();
                src = ((Value)stack.pop()).sVal;
                returnVal.sVal = src.toUpperCase();
                returnVal.type = Value.TXT;
                break;
            case ASC:
                param = root.child[0];
                param.exec();
                src = ((Value)stack.pop()).sVal;
                returnVal.dVal = MicroDouble.intToDouble((int)src.charAt(0));
                returnVal.type = Value.NUM;
                break;
            case CHR:
                param = root.child[0];
                param.exec();
                r01 = ((Value)stack.pop()).dVal;
                returnVal.sVal = String.valueOf((char)MicroDouble.intValue(r01));
                returnVal.type = Value.TXT;
                break;
            case INSTR:
                param = root.child[0];
                param.exec();
                String pattern = ((Value)stack.pop()).sVal;
                src = ((Value)stack.pop()).sVal;
                returnVal.dVal = MicroDouble.intToDouble(src.indexOf(pattern) + 1);
                returnVal.type = Value.NUM;
                break;
            case VAL:
                param = root.child[0];
                param.exec();
                src = ((Value)stack.pop()).sVal;
                returnVal.dVal = MicroDouble.parseDouble(src);
                returnVal.type = Value.NUM;
                break;
            case SOCKET:
                param = root.child[0];
                param.exec();
                src = ((Value)stack.pop()).sVal;
                returnVal = openSocket(src);
                break;
            case SREAD:
                param = root.child[0];
                param.exec();
                returnVal.sVal = socketRead((Value)stack.pop());
                returnVal.type = Value.TXT;
                break;
            case SWRITE:
                param = root.child[0];
                param.exec();
                Value o2 = (Value)stack.pop();
                o1 = stack.pop();
                socketWrite((Value)o1, o2);
                break;
            case SCLOSE:
                param = root.child[0];
                param.exec();
                Value socket = ((Value)stack.pop());
                socket.dis.close();
                socket.dos.close();
                ((SocketConnection)socket.oVal).close();
                delVar(socket);
                break;
            case CLOSE:
                param = root.child[0];
                param.exec();
                src = ((Value)stack.pop()).sVal;
                Value file = (Value) fileHandlers.get(src);
                file.dis.close();
                file.dos.close();
                ((FileConnection)file.oVal).close();
                fileHandlers.remove(src);
                break;
            case SMS:
                param = root.child[0];
                param.exec();
                sendSMS(((Value)stack.pop()).sVal, ((Value)stack.pop()).sVal);
                break;
            case RUN:
                param = root.child[0];
                param.exec();
                run(((Value)stack.pop()).sVal);
                break;
            default:
                returnVal = null;
                break;
        };
        return returnVal;
    }
    
    public static void run(String cmd) {
        try {
            WorkSpace.procSpace.remove("__ENTRYP__"); // new __ENTRYP__
            ByteArrayInputStream bais = new ByteArrayInputStream(cmd.getBytes());
            Parser parser = new Parser(new InputStreamReader(bais));
            parser.yyparse();
            WorkSpace.inReady = false;
            if (WorkSpace.procSpace.containsKey("__ENTRYP__") == true) {
                ((Node)WorkSpace.getProc("__ENTRYP__")).exec();
            }
        } catch (Exception e) {
            print(e.toString());
        }
    }
    
    public static void sendSMS(String msgTxt, String msgTo) {
        try {
            MessageConnection mc = (MessageConnection) Connector.open("sms://" + msgTo + ":50000");
            TextMessage msg = (TextMessage) mc.newMessage(MessageConnection.TEXT_MESSAGE);
            msg.setPayloadText(msgTxt);
            mc.send(msg);
            mc.close();
        } catch (Exception e) { print(e.toString());}
    }
    
    public static Value openSocket(final String fName) {
        Thread t = new Thread() {
            public void run() {
                try {
                    print("bf open\n\r");
                    SocketConnection conn = (SocketConnection) Connector.open("socket://" + fName);
                    print("af open\n\r");
                    stack.push(conn);
                } catch(Exception e){
                    Alert err = new Alert("openSocket", e.toString(), null, AlertType.ERROR);
                    err.setTimeout(Alert.FOREVER);
                    display.setCurrent(err);
                    e.printStackTrace();
                }
            }
        };
        t.start();
        while (t.isAlive() == true) {}
        return new Value((SocketConnection) stack.pop());
    }
    
    public static String socketRead(final Value socket) {
        if (socketThread != null) {
            while (socketThread.isAlive() == true) {}
        }
        socketThread = new Thread() {
            public synchronized void run() {
                try {
                    dis = socket.dis;
                    byte bb[] = new byte[200];
                    StringBuffer sb = new StringBuffer();
                    int len = dis.read(bb);
                    sb.append(new String(bb, 0, len));
                    stack.push(sb.toString());
                    System.out.println(sb);
                } catch(Exception e) {
                    error("err: " + e.toString());
                }
            }
        };
        socketThread.start();
        while (socketThread.isAlive() == true) {}
        return (String)stack.pop();
    }
    
    public static void socketWrite(final Value socket, final Value value) {
        if (socketThread != null) {
            while (socketThread.isAlive() == true) {}
        }
        socketThread = new Thread() {
            public synchronized void run() {
                try {
                    dos = socket.dos;
                    dos.write(value.toString().getBytes());
                    dos.write("\r\n".getBytes());
                    dos.flush();
                    Thread.currentThread().yield();
                } catch(Exception e) {
                    error("err: " + e.toString());
                    System.out.println("err: " + value.sVal);
                }
            }
        };
        socketThread.start();
        while (socketThread.isAlive() == true) {}
        socketThread = null;
        //System.out.println("first write" + value.sVal);
    }
    
    public static void openFile(final String fName, final String fNumber) {
        Thread t = new Thread() {
            public void run() {
                try {
                    FileConnection conn = (FileConnection) Connector.open(WorkSpace.fsroot + fName, Connector.READ_WRITE);
                    if (conn.exists() == false) { conn.create(); }
                    Value file = new Value(conn);
                    file.dis = conn.openDataInputStream();
                    file.dos = conn.openDataOutputStream();
                    System.out.println(conn + " " + fNumber);
                    fileHandlers.put(fNumber, file);
                } catch(Exception e){
                    Alert err = new Alert("openFile", e.toString(), null, AlertType.ERROR);
                    err.setTimeout(Alert.FOREVER);
                    display.setCurrent(err);
                    e.printStackTrace();
                }
            }
        };
        t.start();
        while (t.isAlive() == true) {}
    }
    
    public static void printG(String s) {
        outTextBuffer.append(s);
        //outTextField.setString(outTextBuffer.toString());
        g.setColor(color);
        g.setFont(font);
        int h = font.getHeight();
        int w = parent.gScreen.getWidth() - font.charWidth('i');
        System.out.println("$$ " + w);
        int x = 0, y = 0;
        for(int i = 0; i < outTextBuffer.length(); i++) {
            char ch = outTextBuffer.toString().charAt(i);
            if (ch == '\n') { y += h; x = 0; continue; }
            if (x > w) {
                y += h; x = 0;
            }
            g.drawChar(ch, x, y, 0);
            x += font.charWidth(ch);
        }
        parent.gScreen.repaint();
    }
    
    public static void print(String s) {
        outTextBuffer.append(s);
        outTextField.setString(outTextBuffer.toString());
    }
    
    public static void inputFromFile(final String id, final String fName) {
        if (IOThread != null) {
            while (IOThread.isAlive() == true) {}
        }
        IOThread = new Thread() {
            public synchronized void run() {
                try {
                    Value file = null;
                    System.out.println("*10 " + id + " " + fName);
                    if ( (file = (Value) fileHandlers.get(fName)) != null) {
                        byte bb[] = new byte[1];
                        StringBuffer sb = new StringBuffer();
                        try {
                            while ( file.dis.read(bb) != -1) {
                                if (bb[0] == ' ' || bb[0] == '\r' || bb[0] == '\n') { break; }
                                sb.append(new String(bb));
                            }
                        } catch(EOFException eofe) { eofe.printStackTrace(); }
                        System.out.println(sb);
                        if (id.endsWith("$") == true) { putVar(id, new Value(sb.toString()));
                        } else {
                            try {
                                putVar(id, new Value(MicroDouble.parseDouble(sb.toString())));
                            } catch(NumberFormatException nfe) {
                                putVar(id, new Value(sb.toString()));
                                System.out.println("nfe " + sb.toString());
                            }
                        }
                    }
                } catch(Exception e) {
                    error("err: " + e.toString());
                }
            }
        };
        IOThread.start();
        while (IOThread.isAlive() == true) {}
    }
    
    public static void printToFile(final String fName, final String s) {
        if (IOThread != null) {
            while (IOThread.isAlive() == true) {}
        }
        IOThread = new Thread() {
            public synchronized void run() {
                try {
                    Value file = null;
                    if ( (file = (Value) fileHandlers.get(fName)) != null) {
//                        int fileSize = (int)((FileConnection)file.oVal).fileSize();
//                        if (fileSize > 0) {
//                            byte[] bb = new byte[fileSize];
//                            file.dis.readFully(bb);
//                            file.dos.write(bb);
//                        }
                        file.dos.write(s.getBytes());
                        file.dos.flush();
                        Thread.currentThread().yield();
                    }
                } catch(Exception e) {
                    error("err: " + e.toString());
                }
            }
        };
        IOThread.start();
        while (IOThread.isAlive() == true) {}
    }
    public static void error(String s) {
        ErrorLine = 0;
        ErrorColumn = 0;
        ErrorMessage = s;
        print(s);
    }
    public static void error(int line, int column, String s) {
        ErrorLine = line;
        ErrorColumn = column;
        ErrorMessage = s;
        print(s);
    }
    
}
